use anyhow::Result;
use tokio::io::AsyncWriteExt;

const BUFFER_SIZE: usize = 4096;

#[tokio::main]
async fn main() -> Result<()> {
    println!("Hello, world!");
    let addr = "127.0.0.1:6379";
    let listener = tokio::net::TcpListener::bind(addr).await?;

    loop {
        let (stream, source_addr) = listener.accept().await?;
        println!("Connection from: {}", source_addr);

        tokio::spawn(async move {
            if let Err(e) = process_redis_conn(stream).await {
                eprintln!("Error processing connection: {}", e);
            }
        });
    }
    Ok(())
}

async fn process_redis_conn(mut stream: tokio::net::TcpStream) -> Result<()> {
    let mut vec = Vec::with_capacity(BUFFER_SIZE);

    loop {
        stream.readable().await?;

        match stream.try_read_buf(&mut vec) {
            Ok(0) => {
                break;
            }
            Ok(n) => {
                let rc = String::from_utf8_lossy(&vec);
                println!("Received {} bytes, content is {}", n, rc);
                stream.write_all(b"+PONG\r\n").await?;
            }
            Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
                continue;
            }
            Err(e) => {
                return Err(e.into());
            }
        }
    }
    Ok(())
}

